package cn.com.thinvent.dispatch.service.biz.impl;

import cn.com.thinvent.dispatch.dao.*;
import cn.com.thinvent.dispatch.entity.*;
import cn.com.thinvent.dispatch.entity.dto.AlgorithmActionDTO;
import cn.com.thinvent.dispatch.entity.dto.DataCleanTaskDTO;
import cn.com.thinvent.dispatch.entity.dto.PdfResultDTO;
import cn.com.thinvent.dispatch.entity.response.PagedGridResult;
import cn.com.thinvent.dispatch.entity.response.ReturnModel;
import cn.com.thinvent.dispatch.service.biz.DataCleanTaskService;
import cn.com.thinvent.dispatch.service.biz.util.DataBaseUtil;
import cn.com.thinvent.dispatch.service.biz.util.DataConvertUtils;
import cn.com.thinvent.dispatch.service.biz.util.HttpClientUtil;
import cn.com.thinvent.dispatch.service.biz.util.ScpClientUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.pdf.PdfWriter;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.*;
import java.sql.SQLException;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Component
public class DataCleanTaskServiceImpl implements DataCleanTaskService {
    @Resource
    private DataCleanTaskMapper dataCleanTaskMapper;
    @Resource
    private ModelDatasourceResultMappingMapper modelDatasourceResultMappingMapper;
    @Resource
    private ModelDatasourceMapper modelDatasourceMapper;
    @Resource
    private ModelResultMapper modelResultMapper;
    @Resource
    private DataCleanAlgorithmMapper dataCleanAlgorithmMapper;
    @Resource
    private DataCleanResultMapper dataCleanResultMapper;
    @Resource
    private DataCleanTaskLogMapper dataCleanTaskLogMapper;
    @Resource
    private DataCleaStoreConfigMapper dataCleaStoreConfigMapper;
    @Override
    public PagedGridResult<DataCleanTask> list(String taskName, Integer pageNum, Integer pageSize) {
        PagedGridResult<DataCleanTask> pagedGridResult = new PagedGridResult<>();
        Integer pageBegin = (pageNum - 1) * pageSize;
        List<DataCleanTask> list = dataCleanTaskMapper.queryAllByLimit(taskName, pageBegin, pageSize);
        Long count = dataCleanTaskMapper.count(taskName);
        pagedGridResult.setRows(list);
        pagedGridResult.setRecords(count);
        pagedGridResult.setTotal((Integer.parseInt(count.toString()) + pageSize - 1 )/ pageSize);
        pagedGridResult.setPage(pageNum);
        return pagedGridResult;
    }

    @Override
    public DataCleanTask saveOrUpdate(DataCleanTaskDTO dataCleanTaskDTO) {
        Date date = new Date();
        DataCleanTask dataCleanTask = new DataCleanTask();
        DataConvertUtils.convertDTO2DO(dataCleanTaskDTO, dataCleanTask);
        dataCleanTask.setConfig(JSONArray.toJSONString(dataCleanTaskDTO.getConfig()));
        dataCleanTask.setStioreConfigId(StringUtils.join(dataCleanTaskDTO.getStioreConfigId(), ","));
        if("模型任务".equals(dataCleanTaskDTO.getSourceType())) {

        }
        if("结构化数据源".equals(dataCleanTaskDTO.getSourceType())) {
            Integer sourceId = dataCleanTaskDTO.getSourceId();
            dataCleanTask.setSourceId(sourceId);
        }
        if(dataCleanTaskDTO.getId() == null){
            dataCleanTask.setCreateTime(date);
            dataCleanTask.setUpdateTime(date);
            dataCleanTaskMapper.insert(dataCleanTask);
        }else {
            dataCleanTask.setUpdateTime(date);
            dataCleanTaskMapper.update(dataCleanTask);
        }

        return dataCleanTask;
    }

    public static void main(String[] args) {
        String test = "{\"id\":\"\",\"taskName\":\"测试面积提取\",\"sourceType\":\"模型任务\",\"taskDesc\":\"测试面积提取描述\",\"config\":[{\"id\":1,\"name\":\"面积\",\"regular\":\"(\\\\d+\\\\.\\\\d+|\\\\d)+(平方米|公顷|㎡|亩)\"}],\"datasourceIds\":[],\"stioreConfigId\":[4],\"userId\":\"1\"}";
        DataCleanTaskDTO dataCleanTaskDTO = JSON.parseObject(test, DataCleanTaskDTO.class);
        System.out.println(dataCleanTaskDTO);
    }

    @Override
    public DataCleanTask detail(Integer id) {
        DataCleanTask dataCleanTask = dataCleanTaskMapper.queryById(id);
        return dataCleanTask;
    }

    @Override
    public Integer delete(Integer id) {
        return dataCleanTaskMapper.deleteById(id);
    }

    @Override
    public void actionNow(Integer id) {
        // 1.根据id查询任务
        DataCleanTask dataCleanTask = dataCleanTaskMapper.queryById(id);
        // 2.解析算法执行配置文件
        if(null != dataCleanTask) {
            String config = dataCleanTask.getConfig();
            List<AlgorithmActionDTO> algorithmActionDTOS = JSON.parseArray(config, AlgorithmActionDTO.class);
            if(CollectionUtils.isNotEmpty(algorithmActionDTOS)) {
                algorithmActionDTOS = algorithmActionDTOS.stream().filter(data -> data.getSort() != null).sorted
                        (Comparator.comparing(AlgorithmActionDTO::getSort)).collect(Collectors.toList());
            }
            // 根据数据类型判断数据来源是任务的结果还是数据库的数据
            // 3.判断数据源类型
            if(dataCleanTask.getSourceType().equals("模型任务")) {
                List<ModelDatasourceResultMapping> modelDatasourceResultMappings = modelDatasourceResultMappingMapper.queryByTaskId(dataCleanTask.getSourceId());
                // 获取resutIds
                List<Integer> resultIds = modelDatasourceResultMappings.stream().map
                        (ModelDatasourceResultMapping::getResultId).collect(Collectors.toList());
                List<ModelResult> modelResults = modelResultMapper.queryByIds(resultIds);
                if(CollectionUtils.isNotEmpty(modelResults)) {
                    for(ModelResult modelResult : modelResults) {
                        String content = modelResult.getResult();
                        if(CollectionUtils.isNotEmpty(algorithmActionDTOS)) {
                            for(int i = 0;i <= algorithmActionDTOS.size() - 1;i++) {
                                actionAlgorithms(content, dataCleanTask.getId(), algorithmActionDTOS.get(0), i == algorithmActionDTOS.size() - 1);
                            }
                            dataCleanTask.setStatus("已执行");
                            dataCleanTaskMapper.update(dataCleanTask);
                        }
                    }
                }
            }

            if(dataCleanTask.getSourceType().equals("结构化数据源")) {
                Integer sourceId = dataCleanTask.getSourceId();

                ModelDatasource modelDatasource = modelDatasourceMapper.queryById(sourceId);
                // 进行jdbc数据查询
                try {
                    List<Map<String, Object>> fieldValues = DataBaseUtil.getFieldValues(modelDatasource, 0, 1000);
                    for(Map<String, Object> map : fieldValues) {
                        for (Map.Entry<String, Object> entry : map.entrySet()) {
                            String value = (String) entry.getValue();
                            if(CollectionUtils.isNotEmpty(algorithmActionDTOS)) {
                                for(int i = 0;i <= algorithmActionDTOS.size();i++) {
                                    actionAlgorithms(value, dataCleanTask.getId(), algorithmActionDTOS.get(0), i == algorithmActionDTOS.size());
                                }
                                dataCleanTask.setStatus("已执行");
                                dataCleanTaskMapper.update(dataCleanTask);
                            }
                        }
                    }
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                }
            }

            // 4.记录清洗结果
            String stioreConfigId = dataCleanTask.getStioreConfigId();
            List<Integer> ids = new ArrayList<>();
            if(StringUtils.isNotBlank(stioreConfigId)) {
                String[] s = stioreConfigId.split(",");
                for(String ss :s) {
                    ids.add(Integer.parseInt(ss));
                }
            }
            // 查询存储数据源配置信息
            for(Integer configId : ids) {
                DataCleaStoreConfig dataCleaStoreConfig = dataCleaStoreConfigMapper.queryById(configId);
                if(null != dataCleaStoreConfig) {
                    String storeType = dataCleaStoreConfig.getStoreType();
                    if("文件服务器".equals(storeType)) {
                        uploadFTP(id, dataCleaStoreConfig);
                    }
                    if("数据库".equals(storeType)) {
                        storeDataBase(id, dataCleaStoreConfig);
                    }
                }
            }
        }
    }

    private void storeDataBase(Integer cleanTaskId, DataCleaStoreConfig dataCleaStoreConfig) {
        // 查询清洗任务执行结果
        List<DataCleanResult> dataCleanResults = dataCleanResultMapper.queryByTaskId(cleanTaskId);
        if(CollectionUtils.isNotEmpty(dataCleanResults)) {
            dataCleanResults.stream().forEach(dataCleanResult -> {
                PdfResultDTO pdfResultDTO = new PdfResultDTO();
                pdfResultDTO.setTarget(dataCleanResult.getResultContent());
                pdfResultDTO.setSource(dataCleanResult.getSourceContent());
                // 保存到数据库
                try {
                    DataBaseUtil.insertStore(JSON.toJSONString(pdfResultDTO), dataCleaStoreConfig);
                } catch (SQLException throwables) {
                    throwables.printStackTrace();
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                }
            });
        }
    }

    private void uploadFTP(Integer cleanTaskId, DataCleaStoreConfig dataCleaStoreConfig) {
        // 查询清洗任务执行结果
        List<DataCleanResult> dataCleanResults = dataCleanResultMapper.queryByTaskId(cleanTaskId);
        if(CollectionUtils.isNotEmpty(dataCleanResults)) {
            List<PdfResultDTO> pdfResultDTOS = new ArrayList<>();
            dataCleanResults.stream().forEach(dataCleanResult -> {
                PdfResultDTO pdfResultDTO = new PdfResultDTO();
                pdfResultDTO.setSource(dataCleanResult.getSourceContent());
                pdfResultDTO.setTarget(dataCleanResult.getResultContent());
                pdfResultDTOS.add(pdfResultDTO);
            });
            // 创建一个新的PDF文档
            Document document = new Document();
            try {
                Long seconds = System.currentTimeMillis();
                // 创建一个PDF写入器，并指定输出文件路径
                PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream("D:\\TEMP_PDF\\" +seconds + "result.pdf"));
                // 打开文档以添加内容
                document.open();
                // 添加一段文本
                document.add(new Paragraph(JSON.toJSONString(pdfResultDTOS)));
                // 关闭文档
                document.close();
                // 关闭写入器
                writer.close();
                ScpClientUtil scpClient = ScpClientUtil.getInstance(dataCleaStoreConfig.getUrl(), Integer.parseInt(dataCleaStoreConfig.getPort()),
                        dataCleaStoreConfig.getUserName(), dataCleaStoreConfig.getPwd());
                scpClient.putFile("D://TEMP_PDF//" +seconds + "result.pdf",dataCleaStoreConfig.getPath());
            } catch (DocumentException | FileNotFoundException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 结果执行算法逻辑
     * @param content
     * @param algorithmActionDTO
     */
    private void actionAlgorithms(String content, Integer cleanTaskId, AlgorithmActionDTO algorithmActionDTO, Boolean flag) {
        // 查询算法信息
        
        DataCleanAlgorithm dataCleanAlgorithm = dataCleanAlgorithmMapper.queryById(algorithmActionDTO.getId());
        if(null != dataCleanAlgorithm) {
            String algorithmType = dataCleanAlgorithm.getAlgorithmType();
            if("正则".equals(algorithmType)) {
                // 创建正则表达式模式对象
                Pattern p = Pattern.compile(dataCleanAlgorithm.getRegular());
                // 创建匹配器对象
                Matcher m = p.matcher(content);

                StringBuilder matchesAsString = new StringBuilder();
                // 进行匹配
                while (m.find()) {
                    // 提取匹配到的内容

                    matchesAsString.append(m.group()).append(", "); // 追加匹配结果到matchesAsString

                }
                // 保存命中的结果
                if(flag) {
                    DataCleanResult dataCleanResult = new DataCleanResult();
                    dataCleanResult.setAlgorithmId(algorithmActionDTO.getId());
                    dataCleanResult.setCleanTaskId(cleanTaskId);
                    dataCleanResult.setSourceContent(content);
                    dataCleanResult.setResultContent(matchesAsString.toString());
                    Date date = new Date();
                    dataCleanResult.setCreateTime(date);
                    dataCleanResult.setUpdateTime(date);
                    dataCleanResultMapper.insert(dataCleanResult);
                    // 更改执行状态

                }
                // 保存执行日志
                DataCleanTaskLog dataCleanTaskLog = new DataCleanTaskLog();
                dataCleanTaskLog.setCleanTaskId(cleanTaskId);
                dataCleanTaskLog.setAlgorithmId(algorithmActionDTO.getId());
                dataCleanTaskLog.setContent(content);
                dataCleanTaskLog.setActionSort(algorithmActionDTO.getSort());
                dataCleanTaskLog.setResult(matchesAsString.toString());
                Date date = new Date();
                dataCleanTaskLog.setCreateTime(date);
                dataCleanTaskLog.setUpdateTime(date);
                dataCleanTaskLogMapper.insert(dataCleanTaskLog);
            }
            if("函数".equals(algorithmType)) {
                String url = dataCleanAlgorithm.getUrl();
                String reqType = dataCleanAlgorithm.getReqType();
                String reqParams = dataCleanAlgorithm.getReqParams();
                // 解析reqParams
                JSONObject jsonObject = JSON.parseObject(reqParams);
                String getParams = StringUtils.EMPTY;
                Map<String, Object> postParams = new HashMap<>();
                for (Map.Entry<String, Object> entry : jsonObject.entrySet()) {
                    String key = entry.getKey();
                    Object value = entry.getValue();
                    if("get".equalsIgnoreCase(reqType)) {
                        getParams = getParams + key + "=" + value + "&";
                    }
                    if("post".equalsIgnoreCase(reqType)) {
                        postParams.put(key, value);
                    }
                }
                // get请求
                if("get".equalsIgnoreCase(reqType)) {
                    getParams = getParams.substring(0, getParams.length() - 1);
                    String getResult = HttpClientUtil.doGet(url + "?" + getParams);
                    ReturnModel returnModel = JSON.parseObject(getResult, ReturnModel.class);
                    String data = (String) returnModel.getData();
                    // 保存命中的结果
                    if(flag) {
                        DataCleanResult dataCleanResult = new DataCleanResult();
                        dataCleanResult.setAlgorithmId(algorithmActionDTO.getId());
                        dataCleanResult.setCleanTaskId(cleanTaskId);
                        dataCleanResult.setSourceContent(content);
                        dataCleanResult.setResultContent(data);
                        Date date = new Date();
                        dataCleanResult.setCreateTime(date);
                        dataCleanResult.setUpdateTime(date);
                        dataCleanResultMapper.insert(dataCleanResult);
                    }
                    // 保存执行日志
                    DataCleanTaskLog dataCleanTaskLog = new DataCleanTaskLog();
                    dataCleanTaskLog.setCleanTaskId(cleanTaskId);
                    dataCleanTaskLog.setAlgorithmId(algorithmActionDTO.getId());
                    dataCleanTaskLog.setContent(content);
                    dataCleanTaskLog.setActionSort(algorithmActionDTO.getSort());
                    dataCleanTaskLog.setResult(data);
                    Date date = new Date();
                    dataCleanTaskLog.setCreateTime(date);
                    dataCleanTaskLog.setUpdateTime(date);
                    dataCleanTaskLogMapper.insert(dataCleanTaskLog);
                }
                // post请求
                if("post".equalsIgnoreCase(reqType)) {
                    String postResult = HttpClientUtil.doPost(url, JSONObject.toJSONString(postParams));
                    ReturnModel returnModel = JSON.parseObject(postResult, ReturnModel.class);
                    String data = (String) returnModel.getData();
                    // 保存命中的结果
                    if(flag) {
                        DataCleanResult dataCleanResult = new DataCleanResult();
                        dataCleanResult.setAlgorithmId(algorithmActionDTO.getId());
                        dataCleanResult.setCleanTaskId(cleanTaskId);
                        dataCleanResult.setSourceContent(content);
                        dataCleanResult.setResultContent(data);
                        Date date = new Date();
                        dataCleanResult.setCreateTime(date);
                        dataCleanResult.setUpdateTime(date);
                        dataCleanResultMapper.insert(dataCleanResult);
                    }
                    // 保存执行日志
                    DataCleanTaskLog dataCleanTaskLog = new DataCleanTaskLog();
                    dataCleanTaskLog.setCleanTaskId(cleanTaskId);
                    dataCleanTaskLog.setAlgorithmId(algorithmActionDTO.getId());
                    dataCleanTaskLog.setContent(content);
                    dataCleanTaskLog.setActionSort(algorithmActionDTO.getSort());
                    dataCleanTaskLog.setResult(data);
                    Date date = new Date();
                    dataCleanTaskLog.setCreateTime(date);
                    dataCleanTaskLog.setUpdateTime(date);
                    dataCleanTaskLogMapper.insert(dataCleanTaskLog);
                }
            }
        }
    }
}
